#include "AtlasLayouter.h"
#include "ftutils.h"
#include <TrueText/TextLayout.h>
#include "FontImpl.h"

#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_CACHE_H

#include "ftcache.h"

namespace TrueText {

boost::shared_ptr<AtlasLayout> AtlasLayouter::Layout(int clipWidth, const wchar_t* text)
{
	boost::shared_ptr<AtlasLayout> result(new AtlasLayout());
	if (!font.get())
	{
		TT_FAIL_UNEXPECTED();
		return result;
	}
	result->Metrics.reset(new AtlasMetrics());
	result->Metrics->LineHeight = this->font->GetLineHeight();

	result->Layout.reset(new TextLayout());
	result->Layout->Str = text;
	result->Layout->LineHeight = (int)font->GetLineHeight();

	FT_Size size = this->font->getSize();
	FTC_ScalerRec sr = this->font->getScaler();

	FT_Pos pen_x = 0;
	FT_Pos pen_y = this->font->GetLineHeight() * 64;

	result->Layout->Lines.push_back(Line());
	result->Layout->Metrics.push_back(LineMetrics());

	const wchar_t* currentSymbol = text;
	while (*currentSymbol)
	{
		FT_UInt glyph_index = FTC_CMapCache_Lookup(
			GetCMapCache(),
			reinterpret_cast<FTC_FaceID>(font->getFaceId()),
			-1,
			*currentSymbol);

		FT_Glyph glyph;
		FT_EH(FTC_ImageCache_LookupScaler(GetImageCache(), &sr, FT_LOAD_NO_BITMAP, glyph_index, &glyph, 0));
		//get bounding box
		FT_BBox bbox;
		FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_gridfit, &bbox);

		if (clipWidth > 0 && ((pen_x + bbox.xMax) >> 6) >= clipWidth)
		{
			result->Layout->Lines.push_back(Line());
			result->Layout->Metrics.push_back(LineMetrics());
			pen_y += this->font->GetLineHeight() * 64;
			pen_x = 0;
		}

		pen_x -= bbox.xMin;

		LetterMetrics letter;
		letter.advance = glyph->advance.x >> 10;
		letter.origin = Point((pen_x + 2 * bbox.xMin)>> 6, pen_y >> 6);
		Word w;
		w.IsEnterchar = false;
		w.IsWhitespace = false;
		w.WordStart = currentSymbol;
		w.WordLength = 1;

		result->Layout->Lines.back().Words.push_back(w);
		WordMetrics wm;
		wm.Baseline = (-bbox.yMin) >> 6;
		wm.VOffset = this->font->GetLineHeight() - (bbox.yMax >> 6);
		wm.BearingX = (-bbox.xMin) >> 6;
		wm.Bounds = Dimensions((bbox.xMax >> 6) + 1, font->GetLineHeight()); // Second +1 is for offset between letters
		wm.LetterPositions.push_back(0);
		result->Layout->Metrics.back().Words.push_back(wm);
		result->Layout->Metrics.back().Width = wm.Bounds.Width + 1;

		letter.bounds = Rectangle((pen_x + bbox.xMin) >> 6,
			(pen_y - bbox.yMax) >> 6,
			((pen_x + bbox.xMax) >> 6) - 1,
			(pen_y - bbox.yMin) >> 6);

		result->Metrics->Letters[*currentSymbol] = letter;

		++currentSymbol;	
		pen_x += bbox.xMax;
		pen_x += 64; // 1 pixel offset between letters
	}

	return result;
}

} // namespace TrueText